/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.security.logging;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 循环列表
 *
 * @param <T>
 */
@SuppressWarnings("unchecked")
public class CircularList<T> implements Iterable<T> {
    private T[] data;
    private int head = 0;
    private int tail = 0;
    private int size = 0;

    public CircularList(int size) {
        this.data = (T[]) new Object[size];
    }

    public synchronized void resize(int newsize) {
        if (newsize == this.size) return;

        T[] vals = (T[]) new Object[newsize];
        int i = 0;
        if (newsize > this.size) {
            for (i = 0; i < this.size; i++) {
                vals[i] = this.data[convert(i)];
            }
        }

        int off = this.size - newsize;
        for (i = 0; i < newsize; i++) {
            vals[i] = this.data[convert(i + off)];
        }

        this.data = vals;
        this.head = 0;
        this.tail = i;
    }

    private int convert(int index) {
        return (index + this.head) % this.data.length;
    }

    public boolean isEmpty() {
        return this.head == this.tail;
    }

    public int size() {
        return this.size;
    }

    public int getBufferSize() {
        return this.data.length;
    }

    private void checkIndex(int index) {
        if ((index >= this.size) || (index < 0))
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size);
    }

    public T get(int index) {
        checkIndex(index);
        return this.data[convert(index)];
    }

    public synchronized void add(T o) {
        this.data[this.tail] = o;
        this.tail = ((this.tail + 1) % this.data.length);
        if (this.size == this.data.length) {
            this.head = ((this.head + 1) % this.data.length);
        }
        this.size += 1;
        if (this.size > this.data.length)
            this.size = this.data.length;
    }

    public synchronized void clear() {
        for (int i = 0; i < this.data.length; i++) {
            this.data[i] = null;
        }
        this.head = (this.tail = this.size = 0);
    }

    public List<T> toList() {
        List<T> list = new ArrayList<T>(this.size);
        for (int i = 0; i < this.size; i++) {
            list.add(this.data[convert(i)]);
        }
        return list;
    }

    public String toString() {
        StringBuilder str = new StringBuilder();
        str.append("[");
        for (int i = 0; i < this.size; i++) {
            if (i > 0) {
                str.append(",");
            }
            str.append(this.data[convert(i)]);
        }
        str.append("]");
        return str.toString();
    }

    public Iterator<T> iterator() {
        return new Iterator<T>() {
            int idx = 0;

            public boolean hasNext() {
                return this.idx < CircularList.this.size;
            }

            public T next() {
                return CircularList.this.get(this.idx++);
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}